package laboratoryQ.flatness.ui;

import java.util.List;

import javax.swing.JComponent;

import laboratoryQ.flatness.DiagramData;
import laboratoryQ.flatness.FlatnessUtils;
import laboratoryQ.flatness.ICoordinateTransformer;
import laboratoryQ.flatness.Point;
import laboratoryQ.flatness.RangeInfo;
import laboratoryQ.ui.DrawingJComponent;
import laboratoryQ.ui.draw.AxesDrawer;
import laboratoryQ.ui.draw.DiagramDrawer;
import laboratoryQ.ui.draw.IDrawer;
import laboratoryQ.ui.draw.MultiDrawer;
import laboratoryQ.ui.draw.SieveDrawer;
import laboratoryQ.ui.draw.style.ChainStylizerStylizer;
import laboratoryQ.ui.draw.style.IStylizer;

/**
 * DESIGN NOTE:
 * DrawDiagramOnComponent has 2 responsibilities: create multidrawer and adapt such
 * settings as scaleStep of AxesDrawer. It is bad smell but it donot affect to global
 * design. Let it be corrected on necessity.
 */
public class DrawDiagramOnComponent implements IDiagramList2componentStrategy {
	private Point zeroPoint = new Point(0.0, 0.0);
	private IStylizer stylizer = ChainStylizerStylizer.EMPTY_INSTANCE;

	@Override
	public JComponent dia2component(List<DiagramData> experimentView, String xCaption, String yCaption) {
		RangeInfo rangeInfo = FlatnessUtils.getDiagramsRange(experimentView);
		FlatnessUtils.relaxRangeInfo(rangeInfo, zeroPoint);

		ICoordinateTransformer transformer = FlatnessUtils.generateEasyUITransformer(
				25, 
				rangeInfo, 
				false
		);
		
		MultiDrawer mainDrawer = new MultiDrawer();
		int diaPos = -1;
		if (experimentView.size() > 1) {
			diaPos = 0;
		}
		for (DiagramData dia : experimentView) {
			IDrawer diagramDrawer = new DiagramDrawer(
					dia,
					transformer,
					diaPos
			);
			diaPos += diaPos > -1 ? 1 : 0;
			mainDrawer.getDrawersList().add(diagramDrawer);
		}
		
		AxesDrawer axesDrawer = 
			new AxesDrawer(
					transformer,
					rangeInfo,
					zeroPoint,
					adaptStepsPoint(rangeInfo)
			);
		axesDrawer.setXCaption(xCaption);
		axesDrawer.setYCaption(yCaption);
		mainDrawer.getDrawersList().add(axesDrawer);
		
		DrawingJComponent drawComponent = new DrawingJComponent(mainDrawer);
		drawComponent.setStylizer(stylizer);
		return drawComponent;
	}

	public void setStylizer(IStylizer stylizer) {
		this.stylizer = stylizer;
	}

	private static final double[] STEPS = new double[] { 0.001, 0.1, 1, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000 };
	private static final double PREFERABLE = 7.0;
	private double[] steps = STEPS;
	private double preferalbe = PREFERABLE;

	public void setSteps(double[] steps) {
		this.steps = steps;
	}

	public void setPreferalbe(double preferalbe) {
		this.preferalbe = preferalbe;
	}

	private Point adaptStepsPoint(RangeInfo range) {
		return new Point(
				chooseStep(range.maxX - range.minX),
				chooseStep(range.maxY - range.minY)
		);
	}

	private double chooseStep(double dist) {
		double ans = -1;
		double best = Double.MAX_VALUE;
		for (double cand : steps) {
			double count = dist / cand;
			if (Math.abs(count - preferalbe) < best) {
				ans = cand;
				best = Math.abs(count - preferalbe);
			}
		}
		return ans;
	}

	@Override
	public void onExperimentRunStart(JComponent createdComponent) {
		if (!(createdComponent instanceof DrawingJComponent)) {
			return;
		}
		DrawingJComponent drawComponent = (DrawingJComponent) createdComponent;
		if (!(drawComponent.getDrawer() instanceof MultiDrawer)) {
			return;
		}
		MultiDrawer mdrawer = (MultiDrawer) drawComponent.getDrawer();
		mdrawer.getDrawersList().add(SieveDrawer.WHITE_INSTANCE);
	}
}
